package sz.szsmk.citizencard.model.network;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;

import com.umeng.socialize.sina.helper.MD5;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import sz.szsmk.citizencard.util.Constant;

public class DownloadUtils {

    public DownloadUtils() {
    }

    /**
     * 开始下载
     *
     * @param baseUrl
     * @param filePath
     * @param listener
     */
    public static void download(@NonNull String baseUrl, final String filePath, final JsDownloadListener listener) {

        OkHttpClient client = new OkHttpClient()
                .newBuilder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .addInterceptor(new JsDownloadInterceptor(listener))
                .build();

        listener.onStartDownload();


        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
                }

                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {

                }

                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }}, new SecureRandom());
        } catch (Exception e) {
            e.printStackTrace();
        }

        HostnameVerifier hv1 = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };

        String workerClassName = "okhttp3.OkHttpClient";
        try {
            Class workerClass = Class.forName(workerClassName);
            Field hostnameVerifier = workerClass.getDeclaredField("hostnameVerifier");
            hostnameVerifier.setAccessible(true);
            hostnameVerifier.set(client, hv1);
            Field sslSocketFactory = workerClass.getDeclaredField("sslSocketFactory");
            sslSocketFactory.setAccessible(true);
            sslSocketFactory.set(client, sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }

        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(client)
                .baseUrl(Constant.BASE_URL)
                .build();

        retrofit.create(DownloadService.class)
                .download(baseUrl)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .map(new Func1<ResponseBody, InputStream>() {

                    @Override
                    public InputStream call(ResponseBody responseBody) {
                        return responseBody
                                .byteStream();
                    }
                })
                .observeOn(Schedulers.computation()) // 用于计算任务
                .doOnNext(new Action1<InputStream>() {
                    @Override
                    public void call(InputStream inputStream) {
                        writeFile(inputStream, filePath);
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<InputStream>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        listener.onFail(e.getMessage());
                    }

                    @Override
                    public void onNext(InputStream inputStream) {
                        listener.onFinishDownload();
                    }

                });
    }

    /**
     * 将输入流写入文件
     *
     * @param inputString
     * @param filePath
     */
    private static void writeFile(InputStream inputString, String filePath) {
        FileOutputStream fos = null;
        try {
            File file = new File(filePath);
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            if (file.exists()) {
                file.delete();
            }

            fos = new FileOutputStream(file);

            byte[] b = new byte[1024];

            int len;
            while ((len = inputString.read(b)) != -1) {
                fos.write(b,0,len);
            }
            inputString.close();

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try{
                if(fos !=null){
                    fos.close();
                    fos = null;
                }
            }catch (Exception e){

            }
        }
    }


    /**
     * 判断是否已经下载了最新的APK
     */
    public static boolean hasDownloadLatest(Context mContext, String url) {
        File f = new File(getAppPath(mContext) + "apk/",
                MD5.hexdigest(url) + ".apk");
        if (f.exists()) {
            return true;
        }

        return false;
    }

    /**
     * 安装apk
     */
    public static void installApk(Context mContext, String url) {
        // 获取当前sdcard存储路径
        File apkfile = new File(getAppPath(mContext) + "apk/",
                MD5.hexdigest(url) + ".apk");
        if (!apkfile.exists()) {
            apkfile = createFailFile(getAppPath(mContext) + "apk/failed.apk");
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri contentUri = getFileProviderUri(mContext, new File(apkfile.getAbsolutePath()));
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(new File(apkfile.getAbsolutePath())),
                    "application/vnd.android.package-archive");
        }
        ((Activity) mContext).startActivityForResult(intent, 0x666);
    }

    /**
     * 删除apk
     */
    public static void deleteFile(Context mContext, String url) {
        // 获取当前sdcard存储路径
        File apkfile = new File(getAppPath(mContext) + "apk/",
                MD5.hexdigest(url) + ".apk");
        if (apkfile.exists()) {
            apkfile.delete();
        }
    }

    public static Uri getFileProviderUri(Context context, File file) {
//        return FileProvider.getUriForFile(context, context.getPackageName() + ".FileProvider", file);
//        借用已存在的FileProvider
        return FileProvider.getUriForFile(context, context.getPackageName()+".fileProvider", file);
    }

    /**
     * 创建一个失败的file
     *
     * @return
     */
    public static File createFailFile(String filePath) {
        try {
            File pictureFileDir = new File(filePath).getParentFile();
            if (!pictureFileDir.exists()) {
                pictureFileDir.mkdirs();
            }
            File picFile = new File(filePath);
            if (!picFile.exists())
                picFile.createNewFile();
            return picFile;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 在/storage/emulated/0/com.android.ayplatform/apk/ 存储下载的Apk
     */
    public static String createApkFile(Context context, String url) {
        try {
            File fileDir = new File(getAppPath(context) + "apk/");
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
            File file = new File(fileDir, MD5.hexdigest(url) + ".apk");
            if (!file.exists()) {
                file.createNewFile();
            }
            return file.getAbsolutePath();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 清除apk下载目录下的apk
     */
    public static void deleteApk(final Context mContext) {
        // 开启另一线程删除apk路径下的apk文件
        Thread deleteThreadBackground = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    /**
                     * 删除所有后缀为".apk"的包
                     * */
                    File file = new File(getAppPath(mContext) + "apk/");
                    if (file.exists()) {
                        File temp = null;
                        File[] fileArray = file.listFiles();
                        List<File> filelist = new ArrayList<File>();
                        Collections.addAll(filelist, fileArray);
                        Iterator<File> it = filelist.iterator();
                        while (it.hasNext()) {
                            temp = it.next();
                            if (temp.getName().endsWith(".apk"))//获得文件名，如果后缀为“.apk”，就删除文件
                            {
                                temp.delete();//删除文件
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        deleteThreadBackground.start();
    }

    public static String getAppPath(Context context) {
        String filepath = getSD() + File.separator + context.getPackageName()
                + File.separator;
        return filepath;
    }

    public static String getSD() {
        String filepath = Environment.getExternalStorageDirectory()
                .getAbsolutePath();
        return filepath;
    }
}
